package valueObjects
{
	/* 
		Decription:	Manage Sodoku game state class 
		Created Day: 2008/02/10
		Author: Hoang Minh Duc
	*/

	public class SodokuGameTable
	{
		/* Game table constrains */
		public var SODOKU_PANEL_XSIZE:uint = 3;
		public var SODOKU_PANEL_YSIZE:uint = 3;
		public var MAX_PANEL_VALUE:uint = SODOKU_PANEL_XSIZE * SODOKU_PANEL_YSIZE;
		public var MAX_SODOKU_PANEL_ROW:uint = 3;
		public var MAX_SODOKU_PANEL_COL:uint = 3;
		public var MAXROW:uint = SODOKU_PANEL_YSIZE * MAX_SODOKU_PANEL_ROW;
		public var MAXCOL:uint = SODOKU_PANEL_XSIZE * MAX_SODOKU_PANEL_COL;
		public var MAXTABLE:uint = MAXROW * MAXCOL;
		
		
		/* Sodoku number matrix */ 
		private var gameState:Array;
		private var gameInitialState:Array;
		private var solvedCell:uint;
		/************************************************************************************ 
		 *	Created Day:	2008/02/10														*
		 *	Author: 		Hoang Minh Duc													*
		 *	Decription:		Constructor method for initiatial game state by string value	*
		 *	Input:																			*
		 * 					initialState: array of characters which each charater define	*
		 * 									value of a cell at approriate position			*
		 * 									'0': empty cell, '1'-'9': cell value			*
		 *	Output:																			*
		 ************************************************************************************/
		public function SodokuGameTable(initialState:String)
		{
			var tempArray:Array;
			var i:uint;
			var j:uint;
			var cellnum:uint;
			
			
			gameState = new Array();
			gameInitialState = new Array();
			solvedCell =0;
			// convert array to matrix to init game state
			for(i = 0; i < MAXROW; i++)//loop all row
			{
				tempArray = new Array();
				for(j = 0; j < MAXCOL; j++)//loop all colum
				{
					cellnum = uint(initialState.charAt(i*MAXCOL+j));
					if(cellnum != 0)
						solvedCell++;
					tempArray.push(cellnum);
				}
				gameState.push(tempArray);
				gameInitialState.push(tempArray.concat());
			}
		}
		
		public function get_State_At(x:uint,y:uint):uint
		{
			return gameState[x][y];
		}
		
		public function isDefaultValue(x:uint,y:uint):Boolean
		{
			if(gameInitialState[x][y]!=0)
				return true;
			return false;
		}
		public function get_StringState_At(x:uint,y:uint):String
		{
			trace(gameState[x][y]);
			if(gameState[x][y] == 0)
				return "";
			return String(gameState[x][y]);
		}
		public function set_State_At(x:uint,y:uint,value:uint):void
		{
			if ((value>0)&&(value<=MAX_PANEL_VALUE)&&(!isDefaultValue(x,y))){ //Check game contrains
				//implement toggle state
				if(value != gameState[x][y]) //changed -> update state
				{
					if(gameState[x][y] == 0) //increase solved cell counter
						solvedCell++;
					gameState[x][y]=value;
				}
				else //unchange -> set empty state
				{
					gameState[x][y]=0;
					solvedCell--; //decrease solved cell counter
				}
			}
		}

		public function count_SolvedCell():uint
		{
			return solvedCell;
		}
		
		public function list_gameConflictState():Array
		{
			var resultArray:Array = new Array();
			if(count_SolvedCell() >= MAXTABLE)
			{
				var i:uint;
				var j:uint;
				var tempArray:Array;
				for(i=0; i<MAXROW; i++)
				{
					tempArray = get_confictStateOfRow(i);
					if(tempArray.length>0)
						resultArray.push(tempArray);
				}
				
				for(i=0; i<MAXCOL; i++)
				{
					tempArray = get_confictStateOfColume(i);
					if(tempArray.length>0)
						resultArray.push(tempArray);
				}
				
				for(i=0; i<MAX_SODOKU_PANEL_ROW; i++)
					for(j=0; j<MAX_SODOKU_PANEL_COL; j++)
				{
					tempArray = get_confictStateOfPanel(i,j);
					if(tempArray.length>0)
						resultArray.push(tempArray);
				}
			}
			return resultArray;
		}
		
		public function list_gameConflictAtXY(x:uint,y:uint):Array
		{
			var resultArray:Array = new Array();
			var tempArray:Array;
			tempArray = get_confictStateOfRow(x);
			if(tempArray.length>0)
				resultArray.push(tempArray);
					
			tempArray = get_confictStateOfColume(y);
			if(tempArray.length>0)
				resultArray.push(tempArray);
				
			tempArray = get_confictStateOfPanel(x/SODOKU_PANEL_XSIZE, y/SODOKU_PANEL_YSIZE);
			if(tempArray.length>0)
				resultArray.push(tempArray);
			return resultArray;
		}
		
		public function check_gameFinishState():Boolean
		{
			var tempArray:Array = list_gameConflictState();
			if(count_SolvedCell() < MAXTABLE || tempArray.length > 0)
				return false;
			return true; 
		}
		
		private function get_confictStateOfArray(needCheckArray:Array, typeCheck:String):Array
		{
			var i:uint;
			var j:uint
			var tempArray:Array = new Array();
			for(i=0; i<needCheckArray.length ; i++)
				if(needCheckArray[i]!=0)
					for(j=i+1; j < needCheckArray.length; j++)
						if(needCheckArray[i]==needCheckArray[j]) {
							tempArray.push(new ConflictState(0,j,typeCheck));
							needCheckArray[j]=0;
						}
			return tempArray; 
		}
		
		public function get_confictStateOfRow(r:uint):Array
		{
			var i:uint;
			var tempArray:Array = new Array();
			if(r<MAXROW)
			{
				for(i=0; i<MAXCOL; i++)
					tempArray.push(get_State_At(r,i));
				tempArray=get_confictStateOfArray(tempArray,"row");
				
				for(i=0; i<tempArray.length; i++)
					tempArray[i].X=r;
			}	
			return tempArray;	
		}
		
		public function get_confictStateOfColume(c:uint):Array
		{
			var i:uint;
			var tempArray:Array = new Array();
			if(c<MAXCOL)
			{
				for(i=0; i<MAXROW; i++)
					tempArray.push(get_State_At(c,i));
				tempArray=get_confictStateOfArray(tempArray,"col");
				
				for(i=0; i<tempArray.length; i++) {
					tempArray[i].X=tempArray[i].Y;
					tempArray[i].Y=c;
				}
			}	
			return tempArray;	
		}
		
		public function get_confictStateOfPanel(x:uint,y:uint):Array
		{
			var i:uint;
			var j:uint;
			var tempArray:Array = new Array();
			
			if(x<SODOKU_PANEL_XSIZE && y<SODOKU_PANEL_YSIZE) {
				x=x*SODOKU_PANEL_XSIZE;
				y=y*SODOKU_PANEL_YSIZE;
				for(i=0; i < SODOKU_PANEL_XSIZE; i++)
					for(j=0; j < SODOKU_PANEL_YSIZE; j++)
						tempArray.push(get_State_At(x + i, y + j));
				tempArray=get_confictStateOfArray(tempArray,"panel");
				
				for(i=0; i<tempArray.length; i++) {
					tempArray[i].X=x + (tempArray[i].Y/SODOKU_PANEL_YSIZE);
					tempArray[i].Y=y + (tempArray[i]%SODOKU_PANEL_YSIZE);
				}
			}

			return tempArray;	
		}
	}
}